#include "EventLoop.h"
#include "EpollDispatcher.h"
EventLoop::EventLoop() : EventLoop(string())
{

}

EventLoop::EventLoop(const string threadName) {
    m_isQuit = false;
    m_threadID = this_thread::get_id();
    m_threadName = (threadName == string() ?  "MainThread" : threadName);
    m_dispatcher = new EpollDispatcher(this);
    m_channelMap.clear();

    int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, m_socketPair);
    if(-1 == ret){
        perror("socketpair");
        exit(0);
    }

    auto obj = bind(&EventLoop::readMessage, this);
    Channel* channel = new Channel(m_socketPair[1], FDEvent::ReadEvent,
            obj, nullptr, nullptr, this);
    addTask(channel, ElemType::ADD);
}

int EventLoop::run() {
    m_isQuit = false;

    if(m_threadID != this_thread::get_id()) {
        return -1;
    }

    while (!m_isQuit) {
        m_dispatcher->dispatch();
        processTaskQ();
    }
    return 0;
}

int EventLoop::readMessage() {
    char buf[256];
    read(m_socketPair[1], buf, sizeof (buf));
    return 0;
}

int EventLoop::addTask(Channel* channel, ElemType type) {
    m_mutex.lock();
    ChannelElement* node = new ChannelElement;
    node->channel = channel;
    node->type = type;
    m_taskQ.push(node);
    m_mutex.unlock();

    if(m_threadID == this_thread::get_id()) {
        processTaskQ();
    } else {
        taskWakeup();
    }
    return 0;
}

int EventLoop::processTaskQ() {
    while (!m_taskQ.empty()) {
        m_mutex.lock();
        ChannelElement* node = m_taskQ.front();
        m_taskQ.pop();
        m_mutex.unlock();

        Channel* channel = node->channel;
        if(node->type == ElemType::ADD) {
            add(channel);
        } else if(node->type == ElemType::DELETE) {
            remove(channel);
        } else if(node->type == ElemType::MODIFY) {
            modify(channel);
        }
        delete node;
    }
    return 0;
}

int EventLoop::add(Channel* channel) {
    int fd = channel->getSocket();

    if(m_channelMap.find(fd) == m_channelMap.end()) {
        m_channelMap.insert(make_pair(fd, channel));
        m_dispatcher->setChannel(channel);
        return m_dispatcher->add();
    }
    return -1;
}

int EventLoop::remove(Channel* channel) {
    int fd = channel->getSocket();
    if(m_channelMap.find(fd) == m_channelMap.end()) {
        return -1;
    }
    m_dispatcher->setChannel(channel);
    return m_dispatcher->remove();
}

int EventLoop::modify(Channel* channel) {
    int fd = channel->getSocket();
    if(m_channelMap.find(fd) == m_channelMap.end()) {
        return -1;
    }

    m_dispatcher->setChannel(channel);
    return m_dispatcher->modify();
}

void EventLoop::taskWakeup() {
    const char* msg = "我是要成为海贼王的男人";
    write(m_socketPair[0], msg, strlen(msg));
}

int EventLoop::eventActive(int fd, int event) {
    if(fd < 0) {
        return -1;
    }

    Channel* channel = m_channelMap[fd];
    assert(channel->getSocket() == fd);
    if(event & (int)FDEvent::ReadEvent && channel->readCallback) {
        channel->readCallback(const_cast<void*>(channel->getArg()));
    }

    if(event & (int)FDEvent::WriteEvent && channel->writeCallback) {
        channel->writeCallback(const_cast<void*>(channel->getArg()));
    }

    return 0;
}

int EventLoop::freeChannel(Channel *channel) {
    auto it = m_channelMap.find(channel->getSocket());
    if(it != m_channelMap.end()) {
        close(channel->getSocket());
        delete channel;
    }
    return 0;
}
